#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <strings.h>
#include <cstdio>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <unordered_map>
using namespace std;

#define SIZE 1024

string defaultip="0.0.0.0";
uint16_t defaultport=8080;

class Server
{
public:
    Server(uint16_t port = defaultport, string ip = defaultip)
        : port_(port), ip_(ip), running(false)
    {}

    void Init() // 绑定端口的过程
    {
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            perror("socket error");
            exit(1);
        }

        struct sockaddr_in temp;
        bzero(&temp, sizeof(temp));

        temp.sin_family = AF_INET;
        temp.sin_port = htons(port_);
        temp.sin_addr.s_addr = inet_addr(ip_.c_str());

        if (bind(sockfd_, (struct sockaddr*)&temp, sizeof(temp)) < 0)
        {
            perror("bind error");
            exit(0);
        }
    }

    void CheckUser(struct sockaddr_in&client,string ip,uint16_t port)
    {
        auto pos=online_user.find(ip);
        if(pos==online_user.end())
        {
            online_user.insert({ip,client});

            cout<<"["<<ip<<": "<<port<<"]"<<"add to online_usr"<<endl;
        }
    }

    void Broadcast(string info,string ip,uint16_t port)
    {
        for(auto& user:online_user)
        {
            string message="[";
            message+=ip+":";
            message+=to_string(port);
            message+="]#";
            message+=info;

            socklen_t len=sizeof(user.second);
            sendto(sockfd_,message.c_str(),message.size(),0,(struct sockaddr*)&(user.second),len);
        }
    }

    void Run()
    {
        running = true;
        while (running)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            char buffer[SIZE];
            ssize_t s = recvfrom(sockfd_, buffer, SIZE-1, 0, (struct sockaddr *)&client, &len);

            buffer[s]=0;
            if(s<0) continue;

            uint16_t clientport=ntohs(client.sin_port);
            string clientip=inet_ntoa(client.sin_addr);

            CheckUser(client,clientip,clientport);//看看进群没

            string info=buffer;
            // Broadcast(info,clientip,clientport); //进行转发所有的client
            cerr<<info<<endl;
        }
    }

    ~Server()
    {
        if(sockfd_>0) close(sockfd_);
    }

private:
    int sockfd_;
    uint16_t port_;
    string ip_;
    bool running;
    unordered_map<string,struct sockaddr_in> online_user;
};